#include "block.h"
#include "qcow2.h"
#include "utils.h"
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

static BlockDriver *first_driver = NULL;
static BlockBackend *first_blk = NULL;
static BlockDriverState *first_bs = NULL;

// 块设备驱动
static BlockDriver bdrv_qcow2 = {
    "qcow2",            // format_name
    NULL,               // next
    qcow2_open,         // bdrv_open
    qcow2_close,        // bdrv_close
    qcow2_getlength,    // bdrv_getlength
    qcow2_read,         // bdrv_read
    qcow2_write         // bdrv_write
};

static void bdrv_register(BlockDriver *drv)
{
    drv->next = first_driver;
    first_driver = drv;
}

void bdrv_init(void)
{
    static int initialized = 0;
    if (!initialized) {
        bdrv_register(&bdrv_qcow2);
        initialized = 1;
        report_info("Block driver initialized: qcow2");
    }
}

// 打开块设备 - 返回 BlockDriverState 指针
BlockDriverState* bdrv_open(const char *filename, const char *driver)
{
    BlockDriver *drv;
    BlockDriverState *bs;

    // 检查是否已经打开
    for (bs = first_bs; bs; bs = bs->next) {
        if (bs->filename && strcmp(bs->filename, filename) == 0) {
            bs->refcount++;
            report_info("Reusing existing block device: %s (refcount: %d)", filename, bs->refcount);
            return bs;
        }
    }

    // 创建新的块设备状态
    bs = (BlockDriverState *)qemu_mallocz(sizeof(BlockDriverState));
    bs->refcount = 1;

    if (!driver) {
        // 自动检测格式
        uint8_t buf[1024];
        FILE *f = fopen(filename, "rb");
        if (!f) {
            report_error("Failed to open file for format detection: %s", filename);
            qemu_free(bs);
            return NULL;
        }
        size_t read_size = fread(buf, 1, sizeof(buf), f);
        fclose(f);

        // 检测格式
        if (read_size >= sizeof(QCowHeaderV3) && qcow2_probe(buf, read_size)) {
            driver = "qcow2";
            report_info("Auto-detected format: qcow2");
        } else {
            driver = "raw"; // 默认为 raw 格式
            report_info("Auto-detected format: raw (fallback)");
        }
    }

    // 查找对应的驱动
    for (drv = first_driver; drv; drv = drv->next) {
        if (strcmp(drv->format_name, driver) == 0) {
            report_info("Opening file with driver: %s", driver);
            bs->filename = qemu_strdup(filename);

            // 调用驱动的打开函数
            if (drv->bdrv_open(bs, filename) == 0) {
                // 添加到链表
                bs->next = first_bs;
                first_bs = bs;
                report_info("Block device opened successfully: %s", filename);
                return bs;
            } else {
                report_error("Failed to open block device: %s", filename);
                if (bs->filename) qemu_free(bs->filename);
                qemu_free(bs);
                return NULL;
            }
        }
    }

    report_error("Unsupported driver: %s", driver);
    if (bs->filename) qemu_free(bs->filename);
    qemu_free(bs);
    return NULL;
}

// 关闭块设备
void bdrv_close(BlockDriverState *bs)
{
    if (!bs) return;

    bs->refcount--;
    report_info("Closing block device: %s (refcount: %d)", bs->filename, bs->refcount);

    if (bs->refcount <= 0) {
        // 从链表中移除
        BlockDriverState **prev = &first_bs;
        while (*prev) {
            if (*prev == bs) {
                *prev = bs->next;
                break;
            }
            prev = &(*prev)->next;
        }

        // 调用驱动的关闭函数
        BlockDriver *drv = first_driver;
        while (drv) {
            if (drv->bdrv_close) {
                drv->bdrv_close(bs);
                break;
            }
            drv = drv->next;
        }

        if (bs->filename) qemu_free(bs->filename);
        qemu_free(bs);
        report_info("Block device closed and freed");
    }
}

// 块后端管理
BlockBackend* blk_new(const char *name)
{
    BlockBackend *blk = (BlockBackend *)qemu_mallocz(sizeof(BlockBackend));
    blk->name = qemu_strdup(name);
    blk->next = first_blk;
    first_blk = blk;
    report_info("Created block backend: %s", name);
    return blk;
}

void blk_unref(BlockBackend *blk)
{
    if (!blk) return;

    // 从链表中移除
    BlockBackend **prev = &first_blk;
    while (*prev) {
        if (*prev == blk) {
            *prev = blk->next;
            break;
        }
        prev = &(*prev)->next;
    }

    if (blk->bs) {
        bdrv_close(blk->bs);
    }
    if (blk->name) qemu_free(blk->name);
    qemu_free(blk);
    report_info("Block backend freed: %s", blk->name);
}

BlockBackend* blk_by_name(const char *name)
{
    BlockBackend *blk;
    for (blk = first_blk; blk; blk = blk->next) {
        if (blk->name && strcmp(blk->name, name) == 0) {
            return blk;
        }
    }
    return NULL;
}

int blk_attach(BlockBackend *blk, BlockDriverState *bs)
{
    if (!blk || !bs) return -1;

    if (blk->bs) {
        bdrv_close(blk->bs);
    }

    blk->bs = bs;
    bs->refcount++;
    report_info("Attached block device to backend: %s -> %s", bs->filename, blk->name);
    return 0;
}

BlockDriverState* blk_bs(BlockBackend *blk)
{
    return blk ? blk->bs : NULL;
}

// 列出所有打开的块设备
void bdrv_list(void)
{
    printf("\n=== Open Block Devices ===\n");

    BlockDriverState *bs;
    int count = 0;

    for (bs = first_bs; bs; bs = bs->next) {
        printf("Device %d:\n", ++count);
        printf("  Filename: %s\n", bs->filename);
        printf("  Refcount: %d\n", bs->refcount);
        printf("  Total Sectors: %ld\n", bs->total_sectors);
        printf("  Cluster Size: %d\n", bs->cluster_size);

        // 查找关联的后端
        BlockBackend *blk;
        int backend_count = 0;
        for (blk = first_blk; blk; blk = blk->next) {
            if (blk->bs == bs) {
                if (backend_count == 0) {
                    printf("  Backends: %s", blk->name);
                } else {
                    printf(", %s", blk->name);
                }
                backend_count++;
            }
        }
        if (backend_count == 0) {
            printf("  Backends: (none)");
        }
        printf("\n\n");
    }

    if (count == 0) {
        printf("No block devices open\n");
    }
}

// 包装函数 - 保持向后兼容
int64_t bdrv_getlength(BlockDriverState *bs)
{
    if (!bs) return -1;

    BlockDriver *drv = first_driver;
    while (drv) {
        if (drv->bdrv_getlength) {
            return drv->bdrv_getlength(bs);
        }
        drv = drv->next;
    }
    return -1;
}

int bdrv_read(BlockDriverState *bs, int64_t offset, uint8_t *buf, int64_t bytes)
{
    if (!bs || !buf || bytes < 0) return -1;

    BlockDriver *drv = first_driver;
    while (drv) {
        if (drv->bdrv_read) {
            return drv->bdrv_read(bs, offset, buf, bytes);
        }
        drv = drv->next;
    }
    return -1;
}

int bdrv_write(BlockDriverState *bs, int64_t offset, const uint8_t *buf, int64_t bytes)
{
    if (!bs || !buf || bytes < 0) return -1;

    BlockDriver *drv = first_driver;
    while (drv) {
        if (drv->bdrv_write) {
            return drv->bdrv_write(bs, offset, buf, bytes);
        }
        drv = drv->next;
    }
    return -1;
}

#ifdef __cplusplus
}
#endif